﻿#region Copyright
/// <copyright>
/// Copyright (c) 2008 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

using Osh.Epg;
using Osh.Media;

namespace Osh.Qwerty
{
	public class EpgParser : WorkerBase, IEpgParser, IEpgProvider
	{
		private class EventInfo
		{
			public TimeSpan StartTime { get; set; }
			public string Title { get; set; }
			public string Description { get; set; }
		}

		private QwertyClient _client;
		private Regex _eventRegex = new Regex(
			"else\\s*{\\s*title\\s*=\\s*\".*?>(?<hour>\\d+):(?<minute>\\d+)\\s+(?<title>.*?)</span>\".*?description:\"(?<description>.*?)\"",
			RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant);

		public EpgParser(QwertyClient client)
			: base(typeof(EpgParser).FullName)
		{
			if(client == null)
				throw new ArgumentNullException("client");
			_client = client;
		}

		protected override void DoWork()
		{
			this.StopEvent.WaitOne(TimeSpan.FromSeconds(10));

			//IMedia media = _client.Player.CurrentMedia;

			//int channelId;
			//string epgText = DownloadDaylyEpg(date, channelId);

			//List<EpgEvent> events = ParseDaylyEpg(date, epgText);
		}

		private string DownloadDaylyEpg(DateTime date, int channelId)
		{
			int day = (int)(date.Date - DateTime.Now.Date).TotalDays; // -1 - yesterday, 0 - today, 1 - next day, etc.

			UriBuilder ub = new UriBuilder(_client.ServiceUrlBase);
			ub.Path = "/vmplayer/DayliEpgForChannelAction.do";
			ub.Query = string.Format("day={0}&channelID={1}", day, channelId);

			return _client.GetPage(ub.Uri);
		}

		private List<EpgEvent> ParseDaylyEpg(DateTime date, string epgText)
		{
			date = date.Date;

			List<EventInfo> infos = new List<EventInfo>();
			foreach(Match match in _eventRegex.Matches(epgText))
			{
				if(!match.Success)
					continue;

				int timeHour = int.Parse(match.Groups["hour"].Value);
				int timeMin = int.Parse(match.Groups["minute"].Value);
				string title = HttpUtility.HtmlDecode(match.Groups["title"].Value).Trim();
				string description = HttpUtility.HtmlDecode(match.Groups["description"].Value).Trim();
				if(timeHour < 0 || timeHour > 23 || timeMin < 0 || timeMin > 59)
					continue;
				if(!string.IsNullOrEmpty(title) && title.StartsWith("\"") && title.EndsWith("\"") &&
					title.Length > 2 && title.IndexOf('"', 1, title.Length - 2) == -1)
					title = title.Substring(1, title.Length - 2).Trim();

				if(!string.IsNullOrEmpty(description) && description.StartsWith("- "))
					description = description.Substring(2).Trim();

				TimeSpan startTime = new TimeSpan(timeHour, timeMin, 0);
				EventInfo eventInfo = new EventInfo() { StartTime = startTime, Title = title, Description = description };
				infos.Add(eventInfo);
			}

			List<EpgEvent> events = new List<EpgEvent>();
			if(infos.Count > 0)
			{
				for(int i = 0; i < infos.Count; i++)
				{
					EventInfo eventInfo = infos[i];
					EventInfo nextEventInfo = (i < infos.Count - 1) ? infos[i + 1] : null;

					TimeSpan nextEventStartTime = (nextEventInfo != null ? nextEventInfo.StartTime : new TimeSpan(0, 0, 0));
					DateTime startDateTime = date
						.AddDays(i == 0 && (nextEventInfo == null || eventInfo.StartTime > nextEventInfo.StartTime) ? -1 : 0)
						.Add(eventInfo.StartTime);
					DateTime endDateTime = date.AddDays(i > 0 && eventInfo.StartTime > nextEventStartTime ? 1 : 0).Add(nextEventStartTime);

					events.Add(new EpgEvent(startDateTime, endDateTime, "ru", eventInfo.Title, eventInfo.Description));

					if(i > 0 && eventInfo.StartTime > nextEventStartTime)
						break;
				}
			}
			return events;
		}

		#region IEpgProvider Members
		public ChannelEpg GetChannelEpg(IChannel channel, DateTime startTime, DateTime endTime)
		{
			Channel qwertyChannel = (channel as Channel);
			if(qwertyChannel == null)
				return new ChannelEpg(startTime, endTime);

			int? serverId = qwertyChannel.ServerId ?? _client.ChannelDatabase.GetChannelServerIdBySourceUrl(qwertyChannel.SourceUrl);
			if(serverId == null)
				return new ChannelEpg(startTime, endTime);

			List<EpgEvent> events = new List<EpgEvent>();
			int days = Math.Min(7, (int)(endTime.Date - startTime.Date).TotalDays + 1);
			for(int i = 0; i < days; i++)
			{
				DateTime date = startTime.Date.AddDays(i);
				string epgText = DownloadDaylyEpg(date, serverId.Value);
				List<EpgEvent> dayEvents = ParseDaylyEpg(date, epgText);
				foreach(EpgEvent epgEvent in dayEvents)
					if(epgEvent.EndTime <= startTime || epgEvent.StartTime >= endTime)
						continue;
					else
						events.Add(epgEvent);
			}
			return new ChannelEpg(startTime, endTime, events);
		}
		#endregion
	}
}
